package net.taviscaron.drivenotes.api.action;

import com.googlecode.charts4j.AxisLabelsFactory;
import com.googlecode.charts4j.Color;
import com.googlecode.charts4j.DataUtil;
import com.googlecode.charts4j.Fills;
import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.PieChart;
import com.googlecode.charts4j.Plot;
import com.googlecode.charts4j.Plots;
import com.googlecode.charts4j.Slice;
import com.googlecode.charts4j.XYLineChart;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.taviscaron.drivenotes.api.ApiError;
import net.taviscaron.drivenotes.api.ResponseUtil;
import net.taviscaron.drivenotes.shared.model.entity.Car;
import net.taviscaron.drivenotes.shared.model.entity.User;
import net.taviscaron.drivenotes.shared.service.GarageService;
import net.taviscaron.drivenotes.shared.service.StatisticService;
import net.taviscaron.drivenotes.web.core.Constants;
import net.taviscaron.drivenotes.web.util.ColorUtils;
import org.springframework.beans.factory.annotation.Required;

/**
 * Statistic action
 * @author Andrei Senchuk
 */
public class StatisticAction implements ApiAction {
    private static final float CHART_MAX_COEFFICIENT = 1.2f;
    private static final int PIE_CHART_WIDTH = 500;
    private static final int PIE_CHART_HEIGHT = 200;
    private static final int XY_CHART_WIDTH = 500;
    private static final int XY_CHART_HEIGHT = 300;
    private static final int XY_CHART_Y_AXIS_LABELS = 10;
    private static final Color BACKGROUND_COLOR = Color.newColor("050402");

    private GarageService garageService;
    private StatisticService statisticService;

    @Required
    public void setGarageService(GarageService garageService) {
        this.garageService = garageService;
    }

    @Required
    public void setStatisticService(StatisticService statisticService) {
        this.statisticService = statisticService;
    }

    private String totalCostCircleChart(Car car) {
        Float totalChargingCost = statisticService.calculateTotalChargingCost(car);
        Float totalServiceCost = statisticService.calculateTotalServiceCost(car);
        Float totalCost = totalChargingCost + totalServiceCost;

        if (totalCost == 0) {
            return null;
        }

        int chargingCostPart = (int)(totalChargingCost / totalCost * 100);
        int serviceCostPart = 100 - chargingCostPart;

        List<Slice> slices = new ArrayList<Slice>(2);

        if(chargingCostPart > 0) {
            slices.add(Slice.newSlice(chargingCostPart, ColorUtils.nextColor(), "Charging (" + chargingCostPart + "%)"));
        }

        if(serviceCostPart > 0) {
            slices.add(Slice.newSlice(serviceCostPart, ColorUtils.nextColor(), "Service (" + serviceCostPart + "%)"));
        }

        PieChart chart = GCharts.newPieChart(slices);
        chart.setSize(PIE_CHART_WIDTH, PIE_CHART_HEIGHT);
        chart.setThreeD(true);
        chart.setBackgroundFill(Fills.newSolidFill(BACKGROUND_COLOR));

        return chart.toURLString();
    }

    private String fuelConsumptionTendention(Car car) {
        TreeMap<Integer, Double> fuelConsumptionTendention = statisticService.calculateFuelConsumptionTendention(car);
        if(fuelConsumptionTendention == null || fuelConsumptionTendention.isEmpty()) {
            return null;
        }

        List<Integer> mileage = new ArrayList<Integer>(fuelConsumptionTendention.keySet());
        List<Double> consumption = new ArrayList<Double>(fuelConsumptionTendention.values());

        double chartMax = Collections.max(consumption) * CHART_MAX_COEFFICIENT;

        Plot plot = Plots.newPlot(DataUtil.scaleWithinRange(0, chartMax, consumption));
        XYLineChart chart = GCharts.newXYLineChart(plot);
        chart.addXAxisLabels(AxisLabelsFactory.newNumericAxisLabels(mileage.get(0),
                mileage.get(mileage.size() / 2), mileage.get(mileage.size() - 1)));
        chart.addYAxisLabels(AxisLabelsFactory.newNumericRangeAxisLabels(0, chartMax, chartMax / XY_CHART_Y_AXIS_LABELS));
        chart.setSize(XY_CHART_WIDTH, XY_CHART_HEIGHT);
        chart.setGrid(100, 100.0 / XY_CHART_Y_AXIS_LABELS, 3, 2);
        chart.setBackgroundFill(Fills.newSolidFill(BACKGROUND_COLOR));

        return chart.toURLString();
    }

    public Object execute (HttpServletRequest request, HttpServletResponse response) {
        Long carId = null;
        try {
            String stringCarId = request.getParameter("carId");
            carId = Long.valueOf(stringCarId);
        } catch (Exception e) {
            return ResponseUtil.errorResponse(ApiError.BAD_REQUEST, "car id not specified or it's not a number");
        }

        User user = (User)request.getAttribute(Constants.AUTHORIZED_USER_ATTR_NAME);
        List<Car> cars = garageService.findCarsByOwnerId(user.getId());
        Car car = null;

        for(Car c : cars) {
            if(carId.equals(c.getId())) {
                car = c;
                break;
            }
        }

        if(car != null) {
            String totalCost = totalCostCircleChart(car);
            String fuelConsumption = fuelConsumptionTendention(car);
            return ResponseUtil.successResponse("totalCost", totalCost != null ? totalCost : "", "fuelConsumption", fuelConsumption != null ? fuelConsumption : "");
        } else {
            return ResponseUtil.errorResponse(ApiError.BAD_REQUEST, "no such car");
        }
    }
}
